﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using DistanceLearning.Filters;
using DistanceLearning.Models;
using DistanceLearning.Utils;
using TestEngine;
using WebMatrix.WebData;

namespace DistanceLearning.Controllers
{
    [InitializeSimpleMembership]
    public class ExamTestController : JournalBaseController
    {
        private ExamTest ActiveTest
        {
            get { return Session["ActiveTest"] as ExamTest; }
            set { Session["ActiveTest"] = value; }
        }

        private TestSession _testSession;
        private TestSession TestSession
        {
            get { return _testSession ?? (_testSession = Session["TestSession"] as TestSession); }
            set { Session["TestSession"] = value; _testSession = value; }
        }

        [Authorize]
        public ActionResult Index()
        {
            return View(JournalContext.ExamTests);
        }

        //[Authorize]
        public ActionResult MainPagePartial()
        {
            return PartialView("MainPagePartial", JournalContext.ExamTests);
        }

        public ActionResult RunTest(int testId)
        {
            Session["StartTime"] = DateTime.Now;
            var test = JournalContext.ExamTests.FirstOrDefault(x => x.ExamTestID == testId);

            ActiveTest = JournalContext.ExamTests.FirstOrDefault(t => t.ExamTestID == testId);
            TestSession = TestHelper.CreateSession(test);
            if (TestSession.QuestionsCount == 0)
                return RedirectToAction("Index");

            return RedirectToAction("ProcessQuestion", new { testNumber = 0 });
        }

        public ActionResult ProcessQuestion(int testNumber)
        {
            //var question = ActiveTest.ExamTestQuestions.FirstOrDefault(x => x.ExamTestQuestionID >= questionId);
            var question = TestSession.NextQuestion();
            if (question != null)
            {
                if (question.IsOpenQuestion)
                    return RedirectToAction("OpenQuestion", new { testNumber });
                else
                    return RedirectToAction("ClosedQuestion", new { testNumber });
            }
            return RedirectToAction("TestFinish");
        }

        [HttpGet]
        public ActionResult OpenQuestion(int testNumber)
        {
            // TODO: review!
            if (TestSession == null)
                return RedirectToAction("Index");

            var current = TestSession.GetQuestion();
            var question = JournalContext.ExamTestQuestions.FirstOrDefault(t => t.ExamTestQuestionID == current.QuestionID);
            return View(question);
        }

        [HttpPost]
        public ActionResult OpenQuestion(ExamTestQuestion question, int[] correct)
        {
            TestSession.Answer(TestSession.GetQuestionById(question.ExamTestQuestionID), correct);
            return RedirectToAction("ProcessQuestion", new { testNumber = TestSession.CurrentQuestionNumber });
        }

        public ActionResult TestFinish()
        {
            if (TestSession != null)
            {
                var result = TestSession.GetResult();
                var percentageResult = TestSession.GetPercentageResult();
                
                var concreteTest = new ExamConcreteTest();
                concreteTest.TestID = ActiveTest.ExamTestID;
                concreteTest.UserID = UserId;
                concreteTest.StartTime = (DateTime) Session["StartTime"];
                concreteTest.EndTime = DateTime.Now;
                concreteTest.Result = percentageResult;
                JournalContext.ExamConcreteTests.InsertOnSubmit(concreteTest);
                //JournalContext.SubmitChanges();
                
                foreach (var questionState in result)
                {
                    var qa = new ExamQuestionAnswer();
                    qa.ExamConcreteTest = concreteTest;
                    qa.QuestionID = questionState.Key.QuestionID;
                    qa.UserAnswer = questionState.Value.GetAnswers().Aggregate((a, b) => a + ' ' + b);
                    JournalContext.ExamQuestionAnswers.InsertOnSubmit(qa);
                }
                JournalContext.SubmitChanges();
                TestSession = null;
                return View(concreteTest);
            }
            
            return RedirectToAction("Index");
        }

        public ActionResult Image(int id)
        {
            return File(JournalContext.ExamTestPictures.First(_ => _.ExamTestPictureID == id).Picture as byte[], "image/gif");
        }

        public ActionResult ClosedQuestion(int testNumber)
        {
            var current = TestSession.GetQuestion();
            var question = JournalContext.ExamTestQuestions.FirstOrDefault(t => t.ExamTestQuestionID == current.QuestionID);
            return View(question);
        }

        [HttpPost]
        public ActionResult ClosedQuestion(ExamTestQuestion question, string userVariant)
        {
            TestSession.Answer(TestSession.GetQuestionById(question.ExamTestQuestionID), userVariant);
            return RedirectToAction("ProcessQuestion", new { testNumber = TestSession.CurrentQuestionNumber });
        }

        public ActionResult CreateOpenQuestion(int testId)
        {
            var newQuestion = new ExamTestQuestion {ExamTestID = testId};
            return View(newQuestion);
        }

        [HttpPost]
        public ActionResult CreateOpenQuestion(ExamTestQuestion question, IEnumerable<HttpPostedFileBase> fileUpload,
            IEnumerable<string> variants, IEnumerable<int> corrected)
        {
            var correctedCount = corrected.Count();
            if (corrected == null) RedirectToAction("Index"); // ошибка - не выбрано ни одного правильного ответа
            if (correctedCount == 0) RedirectToAction("Index"); // вопрос должен имеять хотя бы один правильный ответ
            question.AllowMultiAnswer = correctedCount > 1 ? true : false;
            //question.ExamTestID = int.Parse(ExamTestID.ToString());
            JournalContext.ExamTestQuestions.InsertOnSubmit(question);
            JournalContext.SubmitChanges();
            //question = JournalContext.ExamTestQuestions.First(q => q.ExamTestQuestionID == question.ExamTestQuestionID);

            var variantsList = variants.ToList();
            for (int i = 0; i < variantsList.Count; ++i)
            {
                if (string.IsNullOrEmpty(variantsList[i])) continue;
                //var nextVariantId = JournalContext.ExamTestVariants.Max(x => x.ExamTestVariantID) + 1;
                var tVariant = new ExamTestVariant()
                                   {
                                       ExamTestQuestionID = question.ExamTestQuestionID,
                                       //ExamTestVariantID = nextVariantId,
                                       IsCorrect = corrected.Contains(i),
                                       VariantText = variantsList[i],
                                   };
                JournalContext.ExamTestVariants.InsertOnSubmit(tVariant);
            }

            UploadFiles(fileUpload, question);

            JournalContext.SubmitChanges();
            return RedirectToAction("Index");
        }

        public ActionResult CreateClosedQuestion(int testId)
        {
            var newQuestion = new ExamTestQuestion {ExamTestID = testId};
            return View(newQuestion);
        }

        [HttpPost]
        public ActionResult CreateClosedQuestion(ExamTestQuestion question, IEnumerable<HttpPostedFileBase> fileUpload, string variantText)
        {
            JournalContext.ExamTestQuestions.InsertOnSubmit(question);
            JournalContext.SubmitChanges();
            var tVariant = new ExamTestVariant()
                               {
                                   ExamTestQuestionID = question.ExamTestQuestionID,
                                   IsCorrect = true,
                                   VariantText = variantText,
                               };
            JournalContext.ExamTestVariants.InsertOnSubmit(tVariant);

            UploadFiles(fileUpload, question);

            
            JournalContext.SubmitChanges();
            return RedirectToAction("Index");
        }

        private void UploadFiles(IEnumerable<HttpPostedFileBase> fileUpload, ExamTestQuestion question)
        {
            foreach (var file in fileUpload)
            {
                if (file == null) continue;

                var ms = new MemoryStream();
                using (ms)
                {
                    file.InputStream.CopyTo(ms);
                }
                var pictureBuffer = ms.GetBuffer();

                var tPicture = new ExamTestPicture() { Picture = pictureBuffer, ExamTestQuestionID = question.ExamTestQuestionID };
                question.ExamTestPictures.Add(tPicture);
            }
        }

        [HttpGet]
        public ActionResult EditingEdit(int examTestId)
        {
            ViewData["Subjects"] = JournalContext.Subjects;
            var test = JournalContext.ExamTests.FirstOrDefault(t => t.ExamTestID == examTestId);

            if (test == null)
            {
                test = new ExamTest();
                test.ExamTestID = -1;
                return View("CreateTest", test);
            }

            return View("EditingForm", test);
        }

        [HttpPost, ValidateInput(false)]
        public ActionResult EditingEdit(ExamTest test)
        {
            // TODO: fill all properties
            if (test.ExamTestID != -1)
            {
                var sourceTest = JournalContext.ExamTests.FirstOrDefault(t => t.ExamTestID == test.ExamTestID);
                if (sourceTest != null)
                {
                    sourceTest.TestName = test.TestName;
                    JournalContext.SubmitChanges();
                }
            }
            else
            {
                test.ExamTestID = 0;
                JournalContext.ExamTests.InsertOnSubmit(test);
                JournalContext.SubmitChanges();
            }

            return RedirectToAction("Index");
        }
        public ActionResult EditingDelete(int examTestId)
        {
            var entity = JournalContext.ExamTests.FirstOrDefault(e => e.ExamTestID == examTestId);
            if (entity != null)
                JournalContext.ExamTests.DeleteOnSubmit(entity);
            JournalContext.SubmitChanges();
            return RedirectToAction("Index");
        }

        public ActionResult CreateClosedQuestionPartial()
        {
            return PartialView();
        }
        public ActionResult CreateOpenQuestionPartial()
        {
            return PartialView();
        }
    }
}
